package pr.lanmu.aspect;

import cn.hutool.json.JSONConfig;
import cn.hutool.json.JSONUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import pr.lanmu.AppApplication;
import pr.lanmu.config.util.JoinPointUtil;
import pr.lanmu.config.util.Log;

import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;


/**
 * 日志切面AOP
 */
@Aspect
@Component
public class LogAspect {
    private final static JSONConfig JSON_CONFIG = new JSONConfig().setIgnoreNullValue(false);

    /**
     * 拦截方法
     */
    @Pointcut("@annotation(pr.lanmu.annotation.CustomLog)")
    public void methodLog() {
    }

    /**
     * 拦截整个类
     */
    @Pointcut("@within(pr.lanmu.annotation.CustomLog)")
    public void typeLog() {
    }

    @Before("methodLog()")
    public void doMethodLogBefore(JoinPoint joinPoint) {
        doTypeLogBefore(joinPoint);
    }

    @AfterThrowing("methodLog()")
    public void doMethodLogAfterThrowing(JoinPoint joinPoint) {
        doTypeLogAfterThrowing(joinPoint);
    }

    @AfterReturning(returning = "obj", pointcut = "methodLog()")
    public void doMethodLogAfterReturning(JoinPoint joinPoint, Object obj) {
        doTypeLogAfterReturning(joinPoint, obj);
    }

    @Before("typeLog()")
    public void doTypeLogBefore(JoinPoint joinPoint) {
        ConcurrentHashMap<String, Long> map = AppApplication.linkTracingTimes.get();
        if (Objects.nonNull(map)) {
            map.put(joinPoint.getSignature()
                    .toString(), System.currentTimeMillis());
        }
        Log.info("开始----调用 {} 方法，参数为{}", JoinPointUtil.getInfo(joinPoint, true));
    }

    @AfterThrowing("typeLog()")
    public void doTypeLogAfterThrowing(JoinPoint joinPoint) {
        ConcurrentHashMap<String, Long> map = AppApplication.linkTracingTimes.get();
        if (Objects.nonNull(map)) {
            String key = joinPoint.getSignature()
                    .toString();
            Long start = map.get(key);
            map.remove(key);
            Log.error("抛出异常----调用 {} 方法,耗时：{}", JoinPointUtil.getInfo(joinPoint, false), System.currentTimeMillis() - start);
        }
        Log.error("抛出异常----调用 {} 方法", JoinPointUtil.getInfo(joinPoint, false));
    }

    @AfterReturning(returning = "obj", pointcut = "typeLog()")
    public void doTypeLogAfterReturning(JoinPoint joinPoint, Object obj) {
        try {
            obj = JSONUtil.toJsonStr(obj, JSON_CONFIG);
        } catch (Exception ignored) {
        }
        ConcurrentHashMap<String, Long> map = AppApplication.linkTracingTimes.get();
        String key = joinPoint.getSignature()
                .toString();
        if (Objects.nonNull(map)) {
            Long start = map.get(key);
            map.remove(key);
            Log.info("结束----调用 {} 方法,耗时：{},返回 {}", JoinPointUtil.getInfo(joinPoint, false)[0], System.currentTimeMillis() - start, obj);
        }
    }
}
